﻿using System.Collections.Generic;
using UnityEngine;

namespace TinyAsset.Editor
{
    public class BuildAnalyzeTask : IBuildTask
    {
        public bool Execute(BuildContext context)
        {
            Dictionary<string, AssetBundleBuildNode> map = context.assetBundles;
            Dictionary<string, List<AssetBundleBuildNode>> redundancies = RedundancyAnalyze(map);
            OptimizeRedundancy(redundancies, map);
            var loop = LoopDependenceAnalyze(map);
            foreach (var item in loop)
                Debug.LogErrorFormat("Loop dependence has been exist. please fix it -> {0}",item);
            return loop.Count <= 0;
        }

        List<string> LoopDependenceAnalyze(Dictionary<string, AssetBundleBuildNode> map)
        {
            List<string> result = new List<string>();
            HashSet<string> removed = new HashSet<string>();

            while (true)
            {
                int lastSize = removed.Count;
                foreach (var item in map)
                {
                    if (removed.Contains(item.Key))
                        continue;

                    if (item.Value.Children.Count == 0)
                        removed.Add(item.Key);
                    else
                    {
                        bool flag = true;
                        foreach (var item1 in item.Value.Children)
                            if (!removed.Contains(item1.Key))
                                flag = false;
                        if (flag)
                            removed.Add(item.Key);
                    }

                    if (item.Value.Parent.Count == 0)
                        removed.Add(item.Key);
                    else
                    {
                        bool flag = true;
                        foreach (var item1 in item.Value.Parent)
                            if (!removed.Contains(item1.Key))
                                flag = false;
                        if (flag)
                            removed.Add(item.Key);
                    }
                }
                if (removed.Count == lastSize)
                    break;
            }

            foreach (var item in map)
            {
                if (!removed.Contains(item.Key))
                    result.Add(item.Key);
            }

            return result;
        }

        Dictionary<string, List<AssetBundleBuildNode>> RedundancyAnalyze(Dictionary<string, AssetBundleBuildNode> map)
        {
            Dictionary<string, List<AssetBundleBuildNode>> individual = new Dictionary<string, List<AssetBundleBuildNode>>();
            foreach (var item in map)
            {
                foreach (var assetPath in item.Value.Individual)
                {
                    List<AssetBundleBuildNode> nodes;
                    if (!individual.TryGetValue(assetPath, out nodes))
                    {
                        nodes = new List<AssetBundleBuildNode>();
                        individual.Add(assetPath, nodes);
                    }
                    nodes.Add(item.Value);
                }
            }
            return individual;
        }

        void OptimizeRedundancy(Dictionary<string, List<AssetBundleBuildNode>> redundancies, Dictionary<string, AssetBundleBuildNode> map)
        {
            string key = AssetBundleUtility.kSharedAssetBundle;
            foreach (var redundancy in redundancies)
            {
                foreach (var node in redundancy.Value)
                {
                    node.Individual.Remove(redundancy.Key);

                    if (!node.Children.ContainsKey(key))
                        node.Children.Add(key, map[key]);

                    if (!map[key].Assets.Contains(redundancy.Key))
                        map[key].Assets.Add(redundancy.Key);

                    if (!map[key].Parent.ContainsKey(node.AssetBundleName))
                        map[key].Parent.Add(node.AssetBundleName, node);
                }
            }
        }
    }
}